/*
 * This class have the rules to calculate payment history's item
 */
package com.src.uniandes.ecos.tsp.creditscore.algorithm;

import com.src.uniandes.ecos.tsp.creditscore.entity.ClienteProducto;
import com.src.uniandes.ecos.tsp.creditscore.entity.HistorialCrediticio;
import com.src.uniandes.ecos.tsp.creditscore.enums.PaymentHistoryEnum;
import com.src.uniandes.ecos.tsp.creditscore.jpa.ClienteProductoJpaController;
import com.src.uniandes.ecos.tsp.creditscore.jpa.
        HistorialCrediticioJpaController;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author Administrador
 */
public class RulesPaymentHistory {

    /**
     * This method obtains the points for payments on time about a client.
     * @param codigo The client to calculate.
     * @return Number of points for payments on time
     */
    public final double getPointsPaymentsOnTime(final Integer codigo) {
        final HistorialCrediticioJpaController controllerHistorialCrediticio =
                new HistorialCrediticioJpaController();
        final List<HistorialCrediticio> listHistorialCrediticio =
                controllerHistorialCrediticio.findLatestRecords(codigo);
        double[] score = new double[listHistorialCrediticio.size()];
        double finalScore = 0.0;
        HistorialCrediticio tmp = null;
        if (!listHistorialCrediticio.isEmpty()) {
            for (int i = 0; i < listHistorialCrediticio.size(); i++) {
                tmp = listHistorialCrediticio.get(i);
                if (tmp.getEreCodigo().getEreCodigo().
                        equals(Integer.valueOf("1"))) {
                    score[i] = PaymentHistoryEnum.PAYMENT_ON_TIME.getPoints();
                } else if (tmp.getEreCodigo().getEreCodigo().
                        equals(Integer.valueOf("2"))) {
                    score[i] = PaymentHistoryEnum.PAYMENT_30_DAYS_LATE.
                            getPoints();
                } else if (tmp.getEreCodigo().getEreCodigo().
                        equals(Integer.valueOf("3"))) {
                    score[i] = PaymentHistoryEnum.PAYMENT_60_DAYS_LATE.
                            getPoints();
                }
            }
            for (int i = 0; i < score.length; i++) {
                finalScore = finalScore + score[i];
            }
            finalScore = finalScore / score.length;
        }
        return finalScore;
    }

    /**
     * This method returns the points that a client obtains according.
     * to number of accounts asociated
     * @param clientId The client to calculate.
     * @return Number of points according to number of accounts associated
     */
    public final double getPointsNumberOfAccountsAssociated(final Integer
            clientId) {
        final ClienteProductoJpaController controllerCliente =
                new ClienteProductoJpaController();
        double result = 0;
        final int accountsNumber = controllerCliente.
                countClienteProductoEntitiesByProductType(clientId);
        if (accountsNumber < PaymentHistoryEnum.
                ACCOUNT_NUMBER_LESS_EQUAL_THAN_THREE.getPoints()) {
            result = PaymentHistoryEnum.
                    VALUE_ACOUNT_NUMBER_LESS_EQUAL_THAN_THREE.getPoints();
        } else if (accountsNumber >= PaymentHistoryEnum.
                ACCOUNT_NUMBER_LESS_EQUAL_THAN_THREE.getPoints()
                && accountsNumber < PaymentHistoryEnum.
                ACCOUNT_NUMBER_LESS_EQUAL_THAN_SEVEN.getPoints()) {
            result = PaymentHistoryEnum.
                    VALUE_ACCOUNT_NUMBER_LESS_EQUAL_THAN_SEVEN.getPoints();
        } else if (accountsNumber > PaymentHistoryEnum.
                ACCOUNT_NUMBER_GREATER_THAN_SIX.getPoints()) {
            result = PaymentHistoryEnum.
                    VALUE_ACCOUNT_NUMBER_LESS_EQUAL_THAN_SEVEN.getPoints();
        }
        return result;
    }

    /**
     * This method obtains the number of points according to pending debt.
     * @param codigo The client to calculate.
     * @return Number of points according to pending debt.
     */
    public final double getPointsAccordingToDebt(final Integer codigo) {
        final ClienteProductoJpaController controllerCliente =
                new ClienteProductoJpaController();
        List<ClienteProducto> listClienteProducto =
                new ArrayList<ClienteProducto>();
        listClienteProducto = controllerCliente.
                findClienteProductoEntities(codigo);
        double[] score = new double[listClienteProducto.size()];
        double finalScore = 0.0;
        ClienteProducto tmp = null;
        BigDecimal usedCuota;
        BigDecimal availableCuota;
        BigDecimal totalCuota;
        BigDecimal valueToPay;
        BigDecimal totalLoanValue;
        if (!listClienteProducto.isEmpty()) {
            for (int i = 0; i < listClienteProducto.size(); i++) {
                tmp = listClienteProducto.get(i);
                if (tmp.getProducto().getProCodigo().equals(Integer.valueOf("1")
                        ) || tmp.getProducto().getProCodigo().
                        equals(Integer.valueOf("2")) || tmp.getProducto().
                        getProCodigo().equals(Integer.valueOf("3"))) {
                    usedCuota = tmp.getClpCuputi();
                    availableCuota = tmp.getClpCupdis();
                    totalCuota = usedCuota.add(availableCuota);
                    if (usedCuota.divide(totalCuota).doubleValue()
                            < PaymentHistoryEnum.
                            USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_TWENTYFIVE.
                            getPoints()) {
                        score[i] = PaymentHistoryEnum.
                            VALUE_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_TWENTYFIVE.
                            getPoints();
                    } else if (usedCuota.divide(totalCuota).doubleValue()
                            >= PaymentHistoryEnum.
                    USED_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_TWENTYFIVE.
                       getPoints() && usedCuota.divide(totalCuota).doubleValue()
                            < PaymentHistoryEnum.
                    USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_FIFTY.
                        getPoints()) {
                        score[i] = PaymentHistoryEnum.
                    VALUE_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_FIFTY.
                        getPoints();
                    } else if (usedCuota.divide(totalCuota).doubleValue()
                            >= PaymentHistoryEnum.
                         USED_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_FIFTY.
                        getPoints() && usedCuota.divide(totalCuota).
                        doubleValue() < PaymentHistoryEnum.
                        USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_SEVENTYFIVE.
                        getPoints()) {
                        score[i] = PaymentHistoryEnum.
                        VALUE_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_FIFTY.
                                getPoints();
                    } else if (usedCuota.divide(totalCuota).doubleValue()
                            >= PaymentHistoryEnum.
                   USED_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_SEVENTYFIVE.
                            getPoints()
                            && usedCuota.divide(totalCuota).doubleValue()
                            <= PaymentHistoryEnum.
                                USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_ONE.
                            getPoints()) {
                        score[i] = PaymentHistoryEnum.
                  VALUE_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_SEVENTYFIVE.
                            getPoints();
                    }
                } else if (tmp.getProducto().getProCodigo().equals(
                        Integer.valueOf("4")) || tmp.getProducto().
                        getProCodigo().equals(Integer.valueOf("5"))
                        || tmp.getProducto().getProCodigo().
                        equals(Integer.valueOf("6"))) {
                    totalLoanValue = tmp.getClpValdes();
                    valueToPay = tmp.getClpSaldeu();
                    if (valueToPay.divide(totalLoanValue).doubleValue()
                            < PaymentHistoryEnum.
                  USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_THIRTY.getPoints()) {
                        score[i] = PaymentHistoryEnum.
                  VALUE_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_THIRTY.getPoints();
                    } else if (valueToPay.divide(totalLoanValue).doubleValue()
                            >=  PaymentHistoryEnum.
                  USED_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_THIRTY.
                            getPoints() && valueToPay.divide(totalLoanValue).
                            doubleValue() < PaymentHistoryEnum.
                  USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_SIXTY.getPoints()) {
                        score[i] = PaymentHistoryEnum.
                  VALUE_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_SIXTY.getPoints();
                    } else if (valueToPay.divide(totalLoanValue).doubleValue()
                            >= PaymentHistoryEnum.
                  USED_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_SIXTY.
                            getPoints()  &&  valueToPay.divide(totalLoanValue).
                            doubleValue()  < PaymentHistoryEnum.
                  USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_NINETY.
                            getPoints()) {
                        score[i] = PaymentHistoryEnum.
                  VALUE_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_SIXTY.
                                getPoints();
                    } else if (valueToPay.divide(totalLoanValue).doubleValue()
                            >= PaymentHistoryEnum.
                  USED_CREDIT_ACCORDING_TO_DEBT_GREATER_EQUAL_THAN_NINETY.
                            getPoints() && valueToPay.divide(totalLoanValue).
                            doubleValue() <= PaymentHistoryEnum.
                  USED_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_ONE_LOAN.
                            getPoints()) {
                        score[i] = PaymentHistoryEnum.
                  VALUE_CREDIT_ACCORDING_TO_DEBT_LESS_THAN_NINETY.
                            getPoints();
                    }
                }
            }
            for (int i = 0; i < score.length; i++) {
                finalScore = finalScore + score[i];
            }
            finalScore = finalScore / score.length;
        }
        return finalScore;
    }

    /**
     * This method returns the number of negative ratings according to the
     * customer.
     * @param codigo The client to calculate.
     * @return Number of negative ratings.
     */
    public final double getPointsOfNegativeRatings(final Integer codigo) {
        final ClienteProductoJpaController controllerCliente =
                new ClienteProductoJpaController();
        List<ClienteProducto> listClienteProducto =
                new ArrayList<ClienteProducto>();
        listClienteProducto = controllerCliente.
                findClienteProductoEntities(codigo);
        final HistorialCrediticioJpaController controllerHistorialCrediticio =
                new HistorialCrediticioJpaController();
        final List parcialValue = new ArrayList();
        double finalValue = 0.0;
        int count24MonthDebt = 0;
        int count12Months60DayDebt = 0;
        int count12Months30DayDebt = 0;
        int count1224Months60DayDebt = 0;
        int count1224Months30DayDebt = 0;
        for (ClienteProducto tmp : listClienteProducto) {
            //Validating negative ratings in the last 24 months
            count24MonthDebt = controllerHistorialCrediticio.count24MonthsDebt(
                    codigo, tmp.getClienteProductoPK().getClpNumpro());
            if (count24MonthDebt == 0) {
                parcialValue.add(PaymentHistoryEnum.VALUE_24_MONTHS_DEBT.
                        getPoints());
            }
            //Validating 60 day negative rating in the last 12 months
            count12Months60DayDebt = controllerHistorialCrediticio.
                    count12Months60DayDebt(codigo, tmp.getClienteProductoPK().
                    getClpNumpro(), Integer.valueOf("3"));
            if (count12Months60DayDebt > 0) {
               parcialValue.add((PaymentHistoryEnum.VALUE_12_MONTHS_60_DAY_DEBT.
                        getPoints() * count12Months60DayDebt));
            }
            //Validating 30 day negative rating in the last 12 months
            count12Months30DayDebt = controllerHistorialCrediticio.
                    count12Months60DayDebt(codigo, tmp.getClienteProductoPK().
                    getClpNumpro(), Integer.valueOf("2"));
            if (count12Months30DayDebt > 0) {
               parcialValue.add((PaymentHistoryEnum.VALUE_12_MONTHS_30_DAY_DEBT.
                        getPoints() * count12Months30DayDebt));
            }
            //Validating 60 day negative rating in the last 12 to 24 months
            count1224Months60DayDebt = controllerHistorialCrediticio.
                    count12_24Months60DayDebt(codigo, tmp.getClienteProductoPK()
                    .getClpNumpro(), Integer.valueOf("3"));
            if (count1224Months60DayDebt > 0) {
               parcialValue.add((PaymentHistoryEnum.
                       VALUE_12_24_MONTHS_60_DAY_DEBT.getPoints()
                       * count1224Months60DayDebt));
            }
            //Validating 30 day negative rating in the last 12 to 24 months
            count1224Months30DayDebt = controllerHistorialCrediticio.
                    count12_24Months60DayDebt(codigo, tmp.getClienteProductoPK()
                    .getClpNumpro(), 2);
            if (count1224Months30DayDebt > 0) {
                parcialValue.add((PaymentHistoryEnum.
                       VALUE_12_24_MONTHS_30_DAY_DEBT.getPoints()
                       * count1224Months30DayDebt));
            }
        }
        if (!parcialValue.isEmpty()) {
            final Iterator iterator = parcialValue.iterator();
            while (iterator.hasNext()) {
                finalValue = finalValue + Double.parseDouble((iterator.next().
                        toString()));
            }
            finalValue = finalValue / parcialValue.size();
        }
        return finalValue;
    }
}

